import axios from "axios";
import * as fs from "node:fs";
import { Asset, DepItem } from "./types";

// ====== 配置区 ======
const NEXUS_BASE_URL = "http://xxxx/service/rest";
const NEXUS_AUTH = { username: "username", password: "password" };
const REPOSITORY = "npm-hosted";
const 下载全部依赖 = false;
const 下载目录 = "./下载的依赖包";
const 已有依赖清单路径 = "./已有的依赖清单.json";
const 本次下载清单路径 = "./本次下载到的依赖清单.json";
// ====================

// 已有依赖清单，结构：{ [包名]: { [版本]: true } }
let 已有的依赖清单: Record<string, Record<string, true>> = {};

// 读取已有依赖清单
if (fs.existsSync(已有依赖清单路径) && fs.statSync(已有依赖清单路径).isFile()) {
  const arrayedList: Record<string, string[]> = JSON.parse(
    fs.readFileSync(已有依赖清单路径, "utf-8")
  );
  for (const depName in arrayedList) {
    if (!已有的依赖清单[depName]) 已有的依赖清单[depName] = {};
    (arrayedList[depName] || []).forEach((version) => {
      已有的依赖清单[depName][version] = true;
    });
  }
}

// 清理并创建下载目录
if (fs.existsSync(下载目录)) {
  fs.rmSync(下载目录, { recursive: true, force: true });
}
fs.mkdirSync(下载目录);

// axios 实例
const request = axios.create({
  baseURL: NEXUS_BASE_URL,
  auth: NEXUS_AUTH,
});

// 获取依赖列表（分页）
const getItemListPart = (continuationToken?: string) =>
  request({
    url: "/v1/components",
    params: {
      repository: REPOSITORY,
      continuationToken,
    },
  });

const getItemList = async (): Promise<DepItem[]> => {
  let depList: DepItem[] = [];
  let res = await getItemListPart();
  depList.push(...res.data.items);
  while (res.data.continuationToken) {
    console.log("continuationToken", res.data.continuationToken);
    res = await getItemListPart(res.data.continuationToken);
    depList.push(...res.data.items);
  }
  return depList;
};

// 下载单个依赖包
const download = async (asset: Asset, depItem: DepItem) => {
  const res = await request({
    url: asset.downloadUrl,
    method: "get",
    responseType: "arraybuffer",
  });
  let filePath = `${depItem.name}-${asset.npm.version}.tgz`;
  if (depItem.group) {
    const depPath = `%40${depItem.group}`;
    filePath = `${depPath}/${filePath}`;
    const groupDir = `${下载目录}/${depPath}`;
    if (!fs.existsSync(groupDir)) {
      fs.mkdirSync(groupDir, { recursive: true });
    }
  }
  fs.writeFileSync(`${下载目录}/${filePath}`, res.data, { flag: "w" });
  console.log(
    `下载完成: ${depItem.name} ${asset.npm.version} -> ${下载目录}/${filePath}`
  );
};

// 主流程
const run = async () => {
  let depList = await getItemList();

  // 过滤已有依赖
  let filteredList = depList;
  if (!下载全部依赖) {
    filteredList = depList.filter((dep) => {
      dep.assets = dep.assets.filter(
        (asset) => !已有的依赖清单[asset.npm.name]?.[asset.npm.version]
      );
      return dep.assets.length > 0;
    });
  }

  // 下载并更新依赖清单
  for (const item of filteredList) {
    for (const asset of item.assets) {
      await download(asset, item);
      if (!已有的依赖清单[asset.npm.name]) 已有的依赖清单[asset.npm.name] = {};
      已有的依赖清单[asset.npm.name][asset.npm.version] = true;
    }
  }

  // 写入本次下载和总依赖清单
  fs.writeFileSync(本次下载清单路径, JSON.stringify(filteredList, null, 2));
  const arrayedList: Record<string, string[]> = {};
  for (const depName in 已有的依赖清单) {
    arrayedList[depName] = Object.keys(已有的依赖清单[depName]);
  }
  fs.writeFileSync(已有依赖清单路径, JSON.stringify(arrayedList, null, 2));
};

run();
